﻿using System;
using System.Net.Sockets;
using Development.Network.Msg;

namespace Development.Network.Tcp
{
    public class TcpToken : ISender
    {
        public event TcpEventHandle EventClose;

        private readonly object _flagLock = new object();
        private int _linkId;
        private Socket _sokect;
        private TcpServer _server;                      //服务器
        private SocketAsyncEventArgs _recvEventArgs;   //接受异步
        private SocketAsyncEventArgs _sendEventArgs;   //发送异步
        private DateTime _connectDateTime;              //连接的时间
        private DateTime _activeDateTime;             //激活时间
        private bool _sendAsync;                      //标识是否有发送异步事件

        /// <summary>
        /// buffer
        /// </summary>
        private DynamicBuffer _recvSplitBuffer;
        private DynamicBuffer _sendBuffer;
        private byte[] _recvBuffer;     //接收缓存

        private string _address;


        public int LinkId { get { return _linkId; } }

        public TcpToken(TcpServer server, int linkId, int recvBufferSize)
        {
            _server = server;
            _linkId = linkId;
            _recvEventArgs = new SocketAsyncEventArgs();
            _recvEventArgs.UserToken = this;
            _recvEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
            _sendEventArgs = new SocketAsyncEventArgs();
            _sendEventArgs.UserToken = this;
            _sendEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);

            _recvSplitBuffer = new DynamicBuffer(recvBufferSize);
            _sendBuffer = new DynamicBuffer(recvBufferSize);
            _recvBuffer = new byte[recvBufferSize];
            _recvEventArgs.SetBuffer(_recvBuffer, 0, _recvBuffer.Length);
            _sendAsync = false;
        }

        public void InitToken(Socket socket)
        {
            lock (_flagLock)
            {
                _sokect = socket;
                _address = _sokect.RemoteEndPoint.ToString();
                _connectDateTime = DateTime.Now;
                PostRecv();
            }
        }

        public string RemoteEndPoint()
        {
           return _address;
        }

        public bool IsSokectOutTime(int outTimeMs)
        {
            lock (_flagLock)
            {
                if ((DateTime.Now - _activeDateTime).TotalMilliseconds > outTimeMs)
                {
                    return true;
                }
                return false;
            }
        }

        private void OnRecv(SocketAsyncEventArgs e)
        {
            lock(_flagLock)
            {
                if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                {
                    _recvSplitBuffer.WriteBuffer(_recvBuffer, 0, e.BytesTransferred);
                    //开始解包
                    //前四个字节为包的长度，后面的内容是协议数据
                    while (_recvSplitBuffer.DataCount >= 4)
                    {
                        int packetLength = BitConverter.ToInt32(_recvSplitBuffer.Buffer, 0);
                        if ((packetLength <= 0) || (packetLength > 10 * 1024 * 1024) || (_recvSplitBuffer.DataCount > 10 * 1024 * 1024))
                        {
                            //异常包
                            throw new Exception("异常包");
                        }

                        //消息报长度不够，等待下一次处理
                        if (_recvSplitBuffer.DataCount < packetLength)
                        {
                            break;
                        }
                        else
                        {
                            //解析包
                            MsgPacket msg = MsgPacket.SplitPacket(this, _recvSplitBuffer.Buffer, 0, packetLength);
                            //处理完消息包，重置缓存
                            _recvSplitBuffer.Clear(packetLength);
                            //心跳包 不处理
                            if(msg.MsgId != 10)
                            {
                                _server.RecvMsg(msg);
                            }
                        }

                    }
                    //继续投递接收消息
                    PostRecv();
                }
                else
                {
                    throw new Exception("on recv error");
                }
            }
        }

        private void PostRecv()
        {
            bool willRaiseEvent = _sokect.ReceiveAsync(_recvEventArgs);
            if (!willRaiseEvent)
            {
                OnRecv(_recvEventArgs);
            }
        }

        private void OnSend(SocketAsyncEventArgs e)
        {
            lock(_flagLock)
            {
                if (e.BytesTransferred != 0 && e.SocketError == SocketError.Success)
                {
                    _sendBuffer.Clear(e.BytesTransferred);
                    if (_sendBuffer.DataCount > 0)
                    {
                        _sendEventArgs.SetBuffer(_sendBuffer.Buffer, 0, _sendBuffer.DataCount);
                        bool willRaiseEvent = _sokect.SendAsync(_sendEventArgs);
                        if (!willRaiseEvent)
                        {
                            OnSend(_sendEventArgs);
                        }
                    }
                    else
                    {
                        _sendAsync = false;
                    }
                }
                else
                {
                    throw new Exception("on send error");
                }
            }
          
        }
        public void Send(byte[] buffer)
        {
            lock (_flagLock)
            {

                if (_sokect == null)
                {
                    return;
                }
                try
                {
                    _sendBuffer.WriteBuffer(buffer);
                    PostSend();
                }
                catch(Exception)
                {
                }
            }

        }
        private void PostSend()
        {
            if (_sendAsync)
            {
                return;
            }
            if (_sendBuffer.DataCount > 0)
            {
                _sendAsync = true;
                _sendEventArgs.SetBuffer(_sendBuffer.Buffer, 0, _sendBuffer.DataCount);
                bool willRaiseEvent = this._sokect.SendAsync(_sendEventArgs);
                if (!willRaiseEvent)
                {
                    OnSend(_sendEventArgs);
                }
            }
        }

        private void IO_Completed(object sender, SocketAsyncEventArgs e)
        {
            try
            {
                lock (_flagLock)
                {
                    _activeDateTime = DateTime.Now;
                }
                if (e.LastOperation == SocketAsyncOperation.Receive)
                    OnRecv(e);
                else if (e.LastOperation == SocketAsyncOperation.Send)
                    OnSend(e);
                else
                    throw new ArgumentException("The last operation completed on the socket was not a receive or send");
            }
            catch (Exception)
            {
               // Log.WriteLog(ELogLevel.LOG_ERROR, string.Format("IO_Completed {0} error, message: {1}", _sokect.RemoteEndPoint, E.Message));
                _server.CloseToken(this);
            }
            finally
            {
                //防止程序崩溃
            }
        }


        public void Close()
        {
            if (EventClose != null)
            {
                EventClose(this);
            }
            lock(_flagLock)
            {
                if (_sokect != null)
                {
                    try
                    {
                        _sokect.Shutdown(SocketShutdown.Both);
                        _sokect.Close();
                    }
                    catch (Exception) { };
                }
                _sendAsync = false;
                _recvSplitBuffer.Clear();
                _sendBuffer.Clear();
                _sokect = null;
            }
        }
    }
}
